import com.google.common.base.Joiner;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * git地址

 https://gitee.com/yujianlong1988/java8andDisruptor.git
 * 收集器
 * @author yujianlong
 * @create 2018-06-16 11:29
 **/
public class StreamTest2 {


	public static class StreamClass{
		private String name;
		private Integer age;

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public Integer getAge() {
			return age;
		}

		public void setAge(Integer age) {
			this.age = age;
		}

		public StreamClass(String name, Integer age) {
			this.name = name;
			this.age = age;
		}

		public StreamClass() {
		}

		public StreamClass(Integer age) {
			this.age = age;
		}

		@Override
		public String toString() {
			return "StreamClass{" +
					"name='" + name + '\'' +
					", age=" + age +
					'}';
		}
	}

	@Test
	public void stream1(){//常用收集器
		System.out.println(Stream.of("a", "b", "c").collect(Collectors.toList()));
		System.out.println(Stream.of("a", "b", "c","a").collect(Collectors.toSet()));
	}
	@Test
	public void stream2(){//最大字符串
//		System.out.println(IntStream.rangeClosed(1, 100).max().orElse(0));
//		maxBy 传入一个comparator 用来找出最大对象
		Optional<String> collect = Stream.of("a", "b", "c").collect(Collectors.maxBy(String::compareToIgnoreCase));
		System.out.println(collect.orElse(null));



	}

	@Test
	public void stream3(){//最大对象
		String baseStr="qwertyuiopasdfghjklzxcvbnm";
		String randomStr = RandomStringUtils.random(4, baseStr);

		List<StreamClass> collect1 = IntStream.rangeClosed(1, 100).boxed().map(i -> {
			return new StreamClass(RandomStringUtils.random(4, baseStr), i);
		}).collect(Collectors.toList());

		Optional<StreamClass> collect = collect1.stream().collect(Collectors.maxBy(Comparator.comparing(StreamClass::getAge)));
		System.out.println(collect.orElse(null));
	}

	@Test
	public void stream4(){//最大对象变量求和
		String baseStr="qwertyuiopasdfghjklzxcvbnm";
		String randomStr = RandomStringUtils.random(4, baseStr);

		List<StreamClass> collect1 = IntStream.rangeClosed(1, 100).boxed().map(i -> {
			return new StreamClass(RandomStringUtils.random(4, baseStr), i);
		}).collect(Collectors.toList());

		int sum1 = collect1.stream().map(StreamClass::getAge).mapToInt(Integer::intValue).sum();//方法一
		System.out.println(sum1);

		int sum2 = collect1.stream().map(StreamClass::getAge).reduce(0,Integer::sum);//方法二
		System.out.println(sum2);

		int sum3 = collect1.stream().collect(Collectors.summingInt(StreamClass::getAge));//方法三
		System.out.println(sum3);
	}

	@Test
	public void stream5(){//最大对象变量求平均值
		String baseStr="qwertyuiopasdfghjklzxcvbnm";
		String randomStr = RandomStringUtils.random(4, baseStr);

		List<StreamClass> collect1 = IntStream.rangeClosed(1, 100).boxed().map(i -> {
			return new StreamClass(RandomStringUtils.random(4, baseStr), i);
		}).collect(Collectors.toList());

		OptionalDouble average = collect1.stream().map(StreamClass::getAge).mapToInt(Integer::intValue).average();//方法一
		System.out.println(average.orElse(0));

		Double average1 = collect1.stream().collect(Collectors.averagingDouble(StreamClass::getAge));//方法二
		System.out.println(average1);
	}

	@Test
	public void stream6(){//字符串连接
		String baseStr="qwertyuiopasdfghjklzxcvbnm";
		String randomStr = RandomStringUtils.random(4, baseStr);

		List<StreamClass> collect1 = IntStream.rangeClosed(1, 100).boxed().map(i -> {
			return new StreamClass(RandomStringUtils.random(4, baseStr), i);
		}).collect(Collectors.toList());

		String joiningStr = collect1.stream().map(StreamClass::getName).collect(Collectors.joining(","));
		System.out.println(joiningStr);

		//guava也有一个
		String join = Joiner.on(",").join(collect1);//直接打印了对象，否则需要对应字段转换之后
		System.out.println(join);

		String joiningStr1 = collect1.stream().map(Objects::toString).collect(Collectors.joining(","));//java8也可以做到甚至更强大
		System.out.println(joiningStr1);

		String joiningStr2 = collect1.stream().map(StreamClass::getName).collect(Collectors.joining(",","[","]"));
		System.out.println(joiningStr2);//更灵活的拼接字符串

	}

	@Test
	public void stream7(){//广义归约 reducing
		String baseStr="qwertyuiopasdfghjklzxcvbnm";
		String randomStr = RandomStringUtils.random(4, baseStr);

		List<StreamClass> collect1 = IntStream.rangeClosed(1, 100).boxed().map(i -> {
			return new StreamClass(RandomStringUtils.random(4, baseStr), i);
		}).collect(Collectors.toList());
		//求和

		Integer sum = collect1.stream().collect(Collectors.reducing(0, StreamClass::getAge, (i, j) -> i + j));
		System.out.println(sum);

		//求最大对象
		Optional<StreamClass> maxVal = collect1.stream().collect(Collectors.reducing((sc1, sc2) -> {
			if (sc1.getAge() > sc2.getAge()) {
				return sc1;
			}
			return sc2;
			//也可以一个三目运算符搞定 sc1.getAge()>sc2.getAge()?:sc1:sc2
		}));
		System.out.println(maxVal.orElse(null));

		//也可以做到字符串拼接[不推荐使用]
		String joinStr = collect1.stream().collect(Collectors.reducing("", StreamClass::getName, (s1, s2) -> s1 +","+ s2));
		System.out.println(joinStr);

	}


	@Test
	public void stream8(){//分组
		String baseStr="qwertyuiopasdfghjklzxcvbnm";
		String randomStr = RandomStringUtils.random(4, baseStr);

		List<Map<String, Object>> mapList = IntStream.rangeClosed(1, 100).boxed().map(i -> {

			Map<String, Object> ma = new HashMap<>();
			ma.put("name", (RandomStringUtils.random(4, baseStr)));
			ma.put("age", i);
			ma.put("level", ThreadLocalRandom.current().nextInt(1, 5));//级别1-4级
			return ma;
		}).collect(Collectors.toList());

//		System.out.println(ThreadLocalRandom.current().ints(5).boxed().collect(Collectors.toList()));//随机值
//		System.out.println(ThreadLocalRandom.current().ints(20,3,100).boxed().collect(Collectors.toList()));
		//开始按级别分组
		Map<Object, List<Map<String, Object>>> levelList = mapList.stream().collect(Collectors.groupingBy(m -> m.get("level")));
		levelList.forEach((k,v)->{
			System.out.println(k+":"+v);
		});

		System.out.println(StringUtils.center("分组统计数量",100,"="));
		//分组统计数量
		Map<Object, Long> level_count = mapList.stream().collect(Collectors.groupingBy(m -> m.get("level"), Collectors.counting()));
		level_count.forEach((k,v)->{
			System.out.println(k+":"+v);
		});


		System.out.println(StringUtils.center("分组统计年龄之和",100,"="));
		//分组统计年龄之和
		Map<Object, Integer> age_sum = mapList.stream().collect(Collectors.groupingBy(m -> m.get("level"), Collectors.summingInt(m -> Integer.parseInt(m.get("age").toString()))));
		age_sum.forEach((k,v)->{
			System.out.println(k+":"+v);
		});
		System.out.println(StringUtils.center("分组获取年龄列表",100,"="));
		//分组获取年龄列表
		Map<Object, List<Object>> level_age = mapList.stream().collect(Collectors.groupingBy(m -> m.get("level"), Collectors.mapping(m -> m.get("age"), Collectors.toList())));
		level_age.forEach((k,v)->{
			System.out.println(k+":"+v);
		});

		System.out.println(StringUtils.center("分组获取每组年龄最大的map",100,"="));
		Comparator<Map<String, Object>> com=(ma1,ma2)->{
			int ageInt1 = Integer.parseInt(ma1.get("age").toString());
			int ageInt2 = Integer.parseInt(ma2.get("age").toString());
			if (ageInt1>ageInt2) {
				return 1;
			} else if (ageInt1==ageInt2) {
				return 0;
			} else {
				return -1;
			}
		};
		//分组获取每组年龄最大的map
		Map<Object, Map<String, Object>> maxsGroup = mapList.stream().collect(Collectors.groupingBy(
				m -> m.get("level"),
				Collectors.collectingAndThen(Collectors.maxBy(com), Optional::get)

		));
		maxsGroup.forEach((k,v)->{
			System.out.println(k+":"+v);
		});


	}


	@Test
	public void stream9() {//list转map 原始顺序和排序map
		String baseStr = "qwertyuiopasdfghjklzxcvbnm";
		String randomStr = RandomStringUtils.random(4, baseStr);

		List<Map<String, Object>> mapList = IntStream.rangeClosed(1, 1000).boxed().map(i -> {

			Map<String, Object> ma = new HashMap<>();
			ma.put("name", (RandomStringUtils.random(4, baseStr)));
			ma.put("age", i);
			ma.put("level", ThreadLocalRandom.current().nextInt(1, 5));//级别1-4级
			return ma;
		}).collect(Collectors.toList());

		//可能存在 Duplicate key
//		Map<Object, Object> collect = mapList.stream().collect(Collectors.toMap(m -> m.get("name"), m -> m.get("age")));
//
//		System.out.println(collect);
		//如何覆盖重复key
		// BinaryOperator<U> mergeFunction 是合并函数

		Map<Object, Object> collect1=mapList.stream().collect(Collectors.toMap(m -> m.get("name"), m -> m.get("age"),(m1,m2)->m1));
		System.out.println(collect1);
		//以上就可以保证map不出错了
		//但是想要得到一个原始顺序的map怎么办，除非是一个linkedhashmap
//		Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
//				Function<? super T, ? extends U> valueMapper,
//				BinaryOperator<U> mergeFunction,
//				Supplier<M> mapSupplier) {
		LinkedHashMap<Object, Object> collect2 = mapList.stream().collect(Collectors.toMap(m -> m.get("name"), m -> m.get("age"), (m1, m2) -> m1, LinkedHashMap::new));
		System.out.println(collect2);

		//想得到一个排序map 就必须是treeMap
		TreeMap<Object, Object> collect3 = mapList.stream().collect(Collectors.toMap(m -> m.get("name"), m -> m.get("age"), (m1, m2) -> m1, TreeMap::new));
		System.out.println(collect3);

		//想获取一个map的map
		Map<Object, Map<String, Object>> mapmap = mapList.stream().collect(Collectors.toMap(m -> m.get("name"), m -> m, (m1, m2) -> m1));
		System.out.println(mapmap);


	}





}
